package cn.com.wangluotongxin.merchants.service.impl;

import cn.com.wangluotongxin.common.constants.ClientConstants;
import cn.com.wangluotongxin.common.constants.CommonConstant;
import cn.com.wangluotongxin.common.exceptions.BadResponseException;
import cn.com.wangluotongxin.common.utils.TenantUtils;
import cn.com.wangluotongxin.merchants.dto.DMerchantsRoleDto;
import cn.com.wangluotongxin.merchants.dto.RoleDto;
import cn.com.wangluotongxin.merchants.eureka.form.AddMerchantsRoleEditForm;
import cn.com.wangluotongxin.merchants.eureka.form.AddMerchantsRoleForm;
import cn.com.wangluotongxin.merchants.form.RoleEditForm;
import cn.com.wangluotongxin.merchants.form.RoleForm;
import cn.com.wangluotongxin.merchants.model.MerchantsMenu;
import cn.com.wangluotongxin.merchants.model.MerchantsRole;
import cn.com.wangluotongxin.merchants.mapper.MerchantsRoleMapper;
import cn.com.wangluotongxin.merchants.model.MerchantsRoleMenu;
import cn.com.wangluotongxin.merchants.service.IMerchantsMenuService;
import cn.com.wangluotongxin.merchants.service.IMerchantsRoleMenuService;
import cn.com.wangluotongxin.merchants.service.IMerchantsRoleService;
import cn.com.wangluotongxin.merchants.vo.DMerchantsRoleVo;
import cn.com.wangluotongxin.merchants.vo.RoleVo;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 商户管理-角色信息 服务实现类
 * </p>
 *
 * @author AutoGenerator
 * @since 2024-04-26
 */
@Slf4j
@Service
public class MerchantsRoleServiceImpl extends ServiceImpl<MerchantsRoleMapper, MerchantsRole> implements IMerchantsRoleService {

    @Autowired
    private IMerchantsMenuService menuService;
    @Autowired
    private IMerchantsRoleMenuService roleMenuService;

    @Override
    public IPage<DMerchantsRoleVo> getPage(DMerchantsRoleDto dto) {
        Page page = Page.of(dto.getPageNumber(), dto.getPageSize());
        return baseMapper.getPage(page, dto);
    }

    @Override
    public DMerchantsRoleVo detail(Integer id) {
        return baseMapper.detail(id);
    }

    @Override
    public List<MerchantsRole> getByUser(Integer userId) {
        return baseMapper.getByUser(userId);
    }

    @Override
    public List<MerchantsRole> getAllRoles() {
        return baseMapper.getAllRoles();
    }

    @Override
    public List<RoleVo> getAllRoleMenus() {
        return baseMapper.getAllRoleMenus();
    }

    @Override
    public void initRole(String targetTenantId) {
        // 默认数据库角色信息
        List<RoleVo> sourceRoleVos = this.getSourceDefaultRoles(CommonConstant.MYBATIS_TENANT_MASTER);

        TenantUtils.set(targetTenantId, targetTenantId);
        List<MerchantsRole> oldRoles = this.list(new LambdaQueryWrapper<MerchantsRole>()
                .in(MerchantsRole::getSourceId, sourceRoleVos.stream().map(item-> { return item.getId(); }).collect(Collectors.toList())));

        for(RoleVo roleVo : sourceRoleVos) {
            MerchantsRole oldRole = oldRoles.stream().filter(item-> item.getSourceId().equals(roleVo.getId())).findFirst().orElse(null);

            List<Integer> sourceMenuIds = roleVo.getRoleMenus().stream().map(item-> { return item.getMenuId(); }).collect(Collectors.toList());
            List<MerchantsMenu> menus = menuService.list(new LambdaQueryWrapper<MerchantsMenu>()
                    .in(MerchantsMenu::getSourceId, sourceMenuIds)
                    .orderByAsc(MerchantsMenu::getId));
            List<Integer> menuIds = menus.stream().map(item-> { return item.getId(); }).collect(Collectors.toList());
            this.createRole(ObjectUtil.isNotNull(oldRole)? oldRole.getId() : null, roleVo.getId(), roleVo.getRoleName(), roleVo.getRemark(), roleVo.getRoleSort(), menuIds);
        }
        TenantUtils.remove();
    }

    @Override
    public void createRole(Integer id, Integer sourceId, String roleName, String remark, Integer roleSort, List<Integer> menuIds) {
        MerchantsRole role = new MerchantsRole();
        role.setId(id);
        role.setRemark(remark);
        role.setRoleName(roleName);
        role.setRoleSort(roleSort);
        if(id == null) {
            role.setSourceId(sourceId);
            this.save(role);
        }else {
            this.updateById(role);
        }

        roleMenuService.remove(new LambdaQueryWrapper<MerchantsRoleMenu>()
                .eq(MerchantsRoleMenu::getRoleId, role.getId()));
        List<MerchantsRoleMenu> roleMenus = menuIds.stream().map(item-> {
            MerchantsRoleMenu roleMenu = new MerchantsRoleMenu();
            roleMenu.setMenuId(item);
            roleMenu.setRoleId(role.getId());
            return roleMenu;
        }).collect(Collectors.toList());
        roleMenuService.saveBatch(roleMenus);
    }

    @Override
    public void add(AddMerchantsRoleForm form) {
        MerchantsRole merchantsRole = new MerchantsRole();
        BeanUtils.copyProperties(form, merchantsRole);
        this.save(merchantsRole);

        if(ArrayUtil.isAllNotEmpty(form.getMenuIds())){
            List<MerchantsRoleMenu> roleMenus = form.getMenuIds().stream().map(item->{
                MerchantsRoleMenu roleMenu = new MerchantsRoleMenu();
                roleMenu.setMenuId(item);
                roleMenu.setRoleId(merchantsRole.getId());
                return roleMenu;
            }).collect(Collectors.toList());
            roleMenuService.saveBatch(roleMenus);
        }
    }

    @Override
    public void edit(AddMerchantsRoleEditForm form) {
        MerchantsRole merchantsRole = new MerchantsRole();
        BeanUtils.copyProperties(form, merchantsRole);
        this.updateById(merchantsRole);
        updateRoleMenu(merchantsRole, form.getMenuIds());
    }

    @Override
    public IPage<RoleVo> getRolePage(RoleDto dto) {
        Page page = Page.of(dto.getPageNumber(), dto.getPageSize());
        return baseMapper.getRolePage(page, dto);
    }

    @Override
    public RoleVo roleDetail(Integer id) {
        return baseMapper.roleDetail(id);
    }

    @Override
    public void addRole(RoleForm form) {
        MerchantsRole merchantsRole = new MerchantsRole();
        BeanUtils.copyProperties(form, merchantsRole);
        this.save(merchantsRole);

        if(ArrayUtil.isAllNotEmpty(form.getMenuIds())){
            List<MerchantsRoleMenu> roleMenus = form.getMenuIds().stream().map(item->{
                MerchantsRoleMenu roleMenu = new MerchantsRoleMenu();
                roleMenu.setRoleId(merchantsRole.getId());
                roleMenu.setMenuId(item);
                return roleMenu;
            }).collect(Collectors.toList());
            roleMenuService.saveBatch(roleMenus);
        }
    }

    @Override
    public void editRole(RoleEditForm form) {
        MerchantsRole merchantsRole = new MerchantsRole();
        BeanUtils.copyProperties(form, merchantsRole);
        this.updateById(merchantsRole);
        updateRoleMenu(merchantsRole, form.getMenuIds());
    }

    @Override
    public List<RoleVo> getList() {
        return baseMapper.getList();
    }

    private void updateRoleMenu(MerchantsRole merchantsRole, List<Integer> menuIds) {
        if(ArrayUtil.isAllNotEmpty(menuIds)){
            List<MerchantsRoleMenu> roleMenus = roleMenuService.list(new LambdaQueryWrapper<MerchantsRoleMenu>()
                    .eq(MerchantsRoleMenu::getRoleId, merchantsRole.getId()));
            List<Integer> oldMenuIds = roleMenus.stream().map(item-> { return item.getMenuId(); }).collect(Collectors.toList());
            //新增
            List<Integer> newMenuIds = menuIds.stream().filter(item-> !oldMenuIds.contains(item)).collect(Collectors.toList());
            // 删除
            List<Integer> deleteMenuIds = oldMenuIds.stream().filter(item-> !menuIds.contains(item)).collect(Collectors.toList());
            if(ArrayUtil.isAllNotEmpty(newMenuIds)){
                List<MerchantsRoleMenu> newRoleMenus = newMenuIds.stream().map(item->{
                    MerchantsRoleMenu roleMenu = new MerchantsRoleMenu();
                    roleMenu.setRoleId(merchantsRole.getId());
                    roleMenu.setMenuId(item);
                    return roleMenu;
                }).collect(Collectors.toList());
                roleMenuService.saveBatch(newRoleMenus);
            }
            if(ArrayUtil.isAllNotEmpty(deleteMenuIds)){
                roleMenuService.remove(new LambdaQueryWrapper<MerchantsRoleMenu>()
                        .eq(MerchantsRoleMenu::getRoleId, merchantsRole.getId())
                        .in(MerchantsRoleMenu::getMenuId, deleteMenuIds));
            }
        }else {
            roleMenuService.remove(new LambdaQueryWrapper<MerchantsRoleMenu>()
                    .eq(MerchantsRoleMenu::getRoleId, merchantsRole.getId()));
        }
    }

    private List<RoleVo> getSourceDefaultRoles(String masterDataSource) {
        TenantUtils.set(masterDataSource, masterDataSource);
        List<RoleVo> masterDefaultRoleVos = this.getAllRoleMenus();
        if(masterDefaultRoleVos == null || masterDefaultRoleVos.size() <= 0) {
            throw new BadResponseException("未获取到角色权限信息，不可同步");
        }
        TenantUtils.remove();
        return masterDefaultRoleVos;
    }
}
